package me.seu.demo.handler;

import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.mapping.DateProperty;
import co.elastic.clients.elasticsearch._types.mapping.KeywordProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.TextProperty;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.IndexRequest;
import co.elastic.clients.elasticsearch.core.IndexResponse;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import me.seu.demo.common.PagerResult;
import me.seu.demo.common.model.DeviceEventEntity;
import me.seu.demo.common.param.QueryParam;
import org.springframework.stereotype.Service;

/**
 * es store 设备事件消息
 * FIXME: 方法待修改完善
 *
 * @author liangfeihu
 * @since 2023/8/3 13:56
 */
@Slf4j
@Service
public class ElasticsearchDeviceEventHandler {

    @Resource(name = "coElasticsearchClient")
    private ElasticsearchClient elasticsearchClient;

    @Resource
    private ElasticsearchCommonHandler elasticsearchCommonHandler;

    /**
     * 新增单条
     */
    public void saveDeviceEvent(String index, DeviceEventEntity deviceEvent)
            throws Exception {
        if (!validateDeviceEventIndexExist(index)) {
            // 创建索引
            createDeviceEventIndex(index);
        }

        deviceEvent.generateId();
        IndexRequest<DeviceEventEntity> indexRequest = new IndexRequest.Builder<DeviceEventEntity>()
                .index(index)
                .id(deviceEvent.getId())
                .document(deviceEvent)
                .build();
        IndexResponse response = elasticsearchClient.index(indexRequest);
        log.info("[saveDeviceEvent] result={}", response.toString());
    }

    /**
     * 批量新增
     */
    public void saveDeviceEventList(String index, List<DeviceEventEntity> eventList)
            throws Exception {
        if (!validateDeviceEventIndexExist(index)) {
            // 创建索引
            createDeviceEventIndex(index);
        }
        BulkRequest.Builder bulkRequestBuilder = new BulkRequest.Builder();
        eventList.stream()
                .forEach(item -> {
                            item.generateId();
                            bulkRequestBuilder.operations(operation -> operation
                                    .index(builder -> builder
                                            .index(index)
                                            .id(item.getId())
                                            .document(item)
                                    )
                            );
                        }
                );

        BulkResponse response = elasticsearchClient.bulk(bulkRequestBuilder.build());
        if (response.errors()) {
            for (BulkResponseItem item : response.items()) {
                if (ObjectUtil.isNotNull(item.error())) {
                    log.error("[saveEventList] to elasticsearch error: {}",
                            item.error().reason());
                }
            }
        }
        log.info("[saveEventList] result={}", response.toString());
    }

    /**
     * 分页查询
     */
    public PagerResult<DeviceEventEntity> queryPage(String index, String deviceId,
            QueryParam queryParam)
            throws Exception {
        if (!validateDeviceEventIndexExist(index)) {
            // 无索引 无数据
            new PagerResult<>(queryParam.getPageIndex(), queryParam.getPageSize(), 0,
                    new ArrayList<>());
        }
        // 根据条件构造参数查询
        SearchRequest searchRequest = elasticsearchCommonHandler.buildSearchRequest(index, deviceId,
                queryParam);

        // 返回对象List
        List<DeviceEventEntity> resList = new ArrayList<>();
        SearchResponse<DeviceEventEntity> searchResponse = elasticsearchClient.search(
                searchRequest, DeviceEventEntity.class);
        //命中list
        List<Hit<DeviceEventEntity>> hitList = searchResponse.hits().hits();
        long total = searchResponse.hits().total().value();
        for (Hit<DeviceEventEntity> hit : hitList) {
            DeviceEventEntity eventEntity = hit.source();
            resList.add(eventEntity);
        }

        log.info("[resList] json = {}", JSONObject.toJSONString(resList));
        return new PagerResult<>(queryParam.getPageIndex(), queryParam.getPageSize(), total,
                resList);
    }

    private boolean validateDeviceEventIndexExist(String indexName) throws Exception {
        BooleanResponse response = elasticsearchClient.indices()
                .exists(new ExistsRequest.Builder().index(indexName).build());
        return response.value();
    }

    private void createDeviceEventIndex(String indexName) throws Exception {
        //定义索引的别名
        String indexAliasName = indexName + "_alias";
        Map<String, Property> propertyMap = new HashMap<>();
        //构建索引类型
        propertyMap.put("id", new Property(new KeywordProperty.Builder().index(true).build()));
        propertyMap.put("deviceId",
                new Property(new KeywordProperty.Builder().index(true).build()));
        propertyMap.put("eventSymbol",
                new Property(new KeywordProperty.Builder().index(true).build()));
        propertyMap.put("content",
                new Property(new TextProperty.Builder().index(true).analyzer("standard").build()));
        propertyMap.put("messageId",
                new Property(new KeywordProperty.Builder().index(true).build()));
        propertyMap.put("timestamp", new Property(new DateProperty.Builder().index(true).build()));
        propertyMap.put("createTime", new Property(new DateProperty.Builder().index(true).build()));

        //构建设置
        TypeMapping mapping = new TypeMapping.Builder().properties(propertyMap).build();
        IndexSettings indexSettings = new IndexSettings.Builder()
                .numberOfShards(String.valueOf(1))
                .numberOfReplicas(String.valueOf(1))
                .build();
        CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder()
                .index(indexName)
                .mappings(mapping)
                .settings(indexSettings)
                .build();
        //执行创建索引操作并返回结果
        CreateIndexResponse createIndexResponse = elasticsearchClient.indices()
                .create(createIndexRequest);
        log.info("[createDeviceEventIndex] indexName={} response={}", indexName,
                createIndexResponse.toString());
    }

}